package com.futuremind.recyclerviewfastscroll;

import com.futuremind.recyclerviewfastscroll.viewprovider.DefaultScrollerViewProvider;
import com.futuremind.recyclerviewfastscroll.viewprovider.ScrollerViewProvider;
import com.hbb20.utils.SystemUtils;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.app.Context;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

/**
 * Created by mklimczak on 28/07/15.
 */
public class FastScroller extends DirectionalLayout {

    private static final int STYLE_NONE = -1;
    private final RecyclerViewScrollListener scrollListener = new RecyclerViewScrollListener(this);
    private ListContainer recyclerView;

    private Component bubble;
    private Component handle;
    private Text bubbleTextView;

    private int bubbleOffset;
    private int handleColor;
    private int bubbleColor;
    private int bubbleTextAppearance;
    private int scrollerOrientation = 1;

    private int maxVisibility = Component.VISIBLE;

    private boolean manuallyChangingPosition;

    private ScrollerViewProvider viewProvider;
    private SectionTitleProvider titleProvider;


    public FastScroller(Context context) {
        this(context, null);
    }

    public FastScroller(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    public FastScroller(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        maxVisibility = getVisibility();
        setViewProvider(new DefaultScrollerViewProvider());

    }

    /**
     * Attach the {@link FastScroller} to {@link ListContainer}. Should be used after the adapter is set
     * to the {@link ListContainer}. If the adapter implements SectionTitleProvider, the FastScroller
     * will show a bubble with title.
     *
     * @param recyclerView A {@link ListContainer} to attach the {@link FastScroller} to.
     */
    public void setRecyclerView(ListContainer recyclerView) {
        this.recyclerView = recyclerView;
        if (recyclerView.getItemProvider() instanceof SectionTitleProvider)
            titleProvider = (SectionTitleProvider) recyclerView.getItemProvider();
        recyclerView.setScrolledListener(scrollListener);
        invalidateVisibility();
        recyclerView.setComponentStateChangedListener((component, i) -> invalidateVisibility());
        scrollListener.updateHandlePosition(recyclerView);

    }

    /**
     * Set the orientation of the {@link FastScroller}. The orientation of the {@link FastScroller}
     * should generally match the orientation of connected  {@link ListContainer} for good UX but it's not enforced.
     * Note: This method is overridden from {@link DirectionalLayout#setOrientation(int)} but for {@link FastScroller}
     * it has a totally different meaning.
     *
     * @param orientation of the {@link FastScroller}. {@link #VERTICAL} or {@link #HORIZONTAL}
     */
    @Override
    public void setOrientation(int orientation) {
        scrollerOrientation = orientation;
        //switching orientation, because orientation in linear layout
        //is something different than orientation of fast scroller
        super.setOrientation(orientation == HORIZONTAL ? VERTICAL : HORIZONTAL);
    }

    /**
     * Set the background color of the bubble.
     *
     * @param color Color in hex notation with alpha channel, e.g. 0xFFFFFFFF
     */
    public void setBubbleColor(int color) {
        bubbleColor = color;
        invalidate();
    }

    /**
     * Set the background color of the handle.
     *
     * @param color Color in hex notation with alpha channel, e.g. 0xFFFFFFFF
     */
    public void setHandleColor(int color) {
        handleColor = color;
        invalidate();
    }

    /**
     * Sets the text appearance of the bubble.
     *
     * @param textAppearanceResourceId The id of the resource to be used as text appearance of the bubble.
     */
    public void setBubbleTextAppearance(int textAppearanceResourceId) {
        bubbleTextAppearance = textAppearanceResourceId;
        invalidate();
    }

    /**
     * Add a {@link RecyclerViewScrollListener.ScrollerListener}
     * to be notified of user scrolling
     *
     * @param listener
     */
    public void addScrollerListener(RecyclerViewScrollListener.ScrollerListener listener) {
        scrollListener.addScrollerListener(listener);
    }

    private boolean isInEditMode() {
        return false;
    }


    private void applyStyling() {
        if (bubbleColor != STYLE_NONE) setBackgroundTint(bubbleTextView, bubbleColor);
        if (handleColor != STYLE_NONE) setBackgroundTint(handle, handleColor);
        if (bubbleTextAppearance != STYLE_NONE) {
        }


    }

    private void setBackgroundTint(Component view, int color) {

        Element backgroundElement = view.getBackgroundElement();
        if (backgroundElement == null) return;
        Element tintElement = ImageTint.getTintElement(backgroundElement, color);
        Utils.setBackground(view, tintElement);
    }


    private void initHandleMovement() {
        handle.setTouchEventListener(new TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_DOWN || touchEvent.getAction() == TouchEvent.POINT_MOVE) {
                    if (titleProvider != null && touchEvent.getAction() == TouchEvent.PRIMARY_POINT_DOWN)
                        viewProvider.onHandleGrabbed();
                    manuallyChangingPosition = true;
                    float relativePos = getRelativeTouchPosition(touchEvent);
                    setScrollerPosition(relativePos);
                    setRecyclerViewPosition(relativePos);
                    return true;
                } else if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_UP) {
                    manuallyChangingPosition = false;
                    if (titleProvider != null) viewProvider.onHandleReleased();
                    return true;
                }
                return false;
            }
        });
        //延时处理
        mContext.getUITaskDispatcher().delayDispatch(() -> setScrollerPosition(0), 500);
    }

    private float getRelativeTouchPosition(TouchEvent event) {
        if (isVertical()) {
            int index = event.getIndex();
            MmiPoint pointerScreenPosition = event.getPointerScreenPosition(index);
            float y = pointerScreenPosition.getY();
            //150 修正偏移
            float yInParent = y - Utils.getViewRawY(handle) - 150;
            return yInParent / (getHeight() - handle.getHeight());
        } else {
            int index = event.getIndex();
            MmiPoint pointerScreenPosition = event.getPointerScreenPosition(index);
            float x = pointerScreenPosition.getX();
            float xInParent = x - Utils.getViewRawX(handle);
            return xInParent / (getWidth() - handle.getWidth());
        }
    }

    @Override
    public void setVisibility(int visibility) {
        maxVisibility = visibility;
        invalidateVisibility();
    }

    private void invalidateVisibility() {
        if (
                recyclerView.getItemProvider() == null ||
                        recyclerView.getItemProvider().getCount() == 0 ||
                        isRecyclerViewNotScrollable() ||
                        maxVisibility != Component.VISIBLE
        ) {
            super.setVisibility(INVISIBLE);
        } else {
            super.setVisibility(VISIBLE);
        }
    }

    private boolean isRecyclerViewNotScrollable() {
        ItemSizeProvider itemSizeProvider = (ItemSizeProvider) recyclerView.getItemProvider();
        if (isVertical()) {
            return itemSizeProvider.getItemHeight() * recyclerView.getItemProvider().getCount() <= recyclerView.getHeight();
        } else {
            return itemSizeProvider.getItemWidth() * recyclerView.getItemProvider().getCount() <= recyclerView.getWidth();
        }
    }

    private void setRecyclerViewPosition(float relativePos) {
        if (recyclerView == null) return;
        int itemCount = recyclerView.getItemProvider().getCount();
        int targetPos = (int) Utils.getValueInRange(0, itemCount - 1, (int) (relativePos * (float) itemCount));
        recyclerView.scrollTo(targetPos);
        if (titleProvider != null && bubbleTextView != null)
            bubbleTextView.setText(titleProvider.getSectionTitle(targetPos));
    }


    void setScrollerPosition(float relativePos) {

        if (isVertical()) {
            bubble.setTranslationY(Utils.getValueInRange(
                    0,
                    getHeight() - bubble.getHeight() - handle.getHeight(),
                    relativePos * (getHeight() - handle.getHeight()) + bubbleOffset)
            );

            handle.setTranslationY(Utils.getValueInRange(
                    0,
                    getHeight() - handle.getHeight() - AttrHelper.vp2px(4, mContext),
                    relativePos * (getHeight() - handle.getHeight())) - bubble.getHeight());

        } else {
            bubble.setTranslationX(Utils.getValueInRange(
                    0,
                    getWidth() - bubble.getWidth(),
                    relativePos * (getWidth() - handle.getWidth()) + bubbleOffset)
            );
            handle.setTranslationX(Utils.getValueInRange(
                    0,
                    getWidth() - handle.getWidth(),
                    relativePos * (getWidth() - handle.getWidth())) - bubble.getWidth()
            );
        }
    }

    public boolean isVertical() {
        return scrollerOrientation == VERTICAL;
    }

    boolean shouldUpdateHandlePosition() {
        return handle != null && !manuallyChangingPosition && recyclerView.getChildCount() > 0;
    }

    ScrollerViewProvider getViewProvider() {
        return viewProvider;
    }

    /**
     * Enables custom layout for {@link FastScroller}.
     *
     * @param viewProvider A {@link ScrollerViewProvider} for the {@link FastScroller} to use when building layout.
     */
    public void setViewProvider(ScrollerViewProvider viewProvider) {
        removeAllComponents();
        this.viewProvider = viewProvider;
        viewProvider.setFastScroller(this);
        bubble = viewProvider.provideBubbleView(this);
        handle = viewProvider.provideHandleView(this);
        bubbleTextView = viewProvider.provideBubbleTextView();
        addComponent(bubble);
        addComponent(handle);
        //初始化移动位置
        initHandleMovement();
        bubbleOffset = viewProvider.getBubbleOffset();
        applyStyling();
        //没有InsetDrawable ，只能去设置MarginRight
        DirectionalLayout.LayoutConfig layoutConfig = (LayoutConfig) bubble.getLayoutConfig();
        layoutConfig.setMarginRight((int) SystemUtils.vp2px(mContext, 18));
        bubble.setLayoutConfig(layoutConfig);
    }

}

